export { }
// 创建一个长度为length的数组   里边的值用value填充
function createArray(length: number, value: any): Array<any> {
  let result: Array<any> = []
  for (let index = 0; index < length; index++) {
    result[index] = value
  }
  return result
}
let rest: Array<string> = createArray(3, 'smd')
console.log(rest) // [ 'smd', 'smd', 'smd' ]

/**
 * 如果想给createArray定义规范，输入的value是什么类型   返回值就是什么类型 就用到了泛型
 * 将以上函数做如下改造
 */
namespace a {
  function createArray<T>(length: number, value: T): Array<T> {
    let result: Array<T> = []
    for (let index = 0; index < length; index++) {
      result[index] = value
    }
    return result
  }
  let rest: Array<number> = createArray(2, 1)
  console.log(rest) // [ 1, 1 ]
}

// 多余参数  用重载的形式
function sum(...nums: any): void
function sum() {
  let args: IArguments = arguments
  console.log(args);
}
sum(1, 2, 3)

// 泛型类
class MyArray<T> {
  private list: T[] = []
  add(value: T) {
    return this.list.push(value)
  }
  get0Value(): T {
    return this.list[0]
  }
}
let myarr = new MyArray<number>()
myarr.add(1)
myarr.add(2)
console.log(myarr.get0Value()); // 1

// 泛型与new
function factory<T>(type: { new(): T }): T { // 描述type形状时，使用泛型用大括号括起来
  return new type()
}
class Person { }
let p = factory<Person>(Person)
console.log(p)

// 泛型接口
interface Add { // 如果将泛型写在接口内部 则定义变量的时候  泛型要定义在函数上  调用函数的时候需要传入具体类型
  <T>(a: T, b: T): T
}

let sum1: Add = function <T>(a: T, b: T) {
  return a
}
let sum2: Add = <T>(a: T, b: T) => {
  return a
}
// let sum: Add = function <T>(a: T, b: T) {
//   return a+b // TODO
// }
sum2<number>(1, 2)

interface Add2<T> { // 如果将泛型定义在接口上  则定义变量的时候  需要将具体类型定义好  调用函数的时候不需要传具体类型了
  (a: T, b: T): T
}
let sum3: Add2<number> = (a, b) => {
  return a + b
}
sum3(1, 2)

interface Add3<T> { // 如果将泛型既定义在接口上  又定义在接口内部  则定义变量的时候  需要在将接口的类型定义好  调用函数的时候也需要传入具体类型
  <U>(a: T, b: T): U
}
let sum4: Add3<number> = <U>(a: number, b: number): U => {
  return (a + b) as any
}
sum4<number>(2, 1)


// 定义多个泛型
function swap<A, B>(tuple: [A, B]): [B, A] { // 定义函数 泛型类型是<A,B> 入参是元组[A,B] 返回参数是[B,A]
  return [tuple[1], tuple[0]]
}
console.log(swap(['smd', 18])) // [ 18, 'smd' ]

// 给泛型指定默认类型
interface Add4<T = number> { }
// 允许 type sum5 = Add4
interface Add5<T> {

}
// 错误  type sum6 = Add5  泛型类型“Add5<T>”需要 1 个类型参数。


// 泛型约束
interface LengthWise {
  length: number
}
function logger<T extends LengthWise>(val: T) {
  // T类型可以通过继承接口的形式 来约束变量val存在length属性   但是ts中泛型的继承和类中的继承不同，ts中泛型的继承是指T类型要和父类只多不能少的属性，至于是不是父类的子类不做要求  这属于ts的兼容性
  console.log(val.length)
}

// namespace a {
//   // 相加
//   interface Add {
//     <T extends number|string>(a: T, b: T): T
//   }
//   let sum: Add = <T extends number|string>(a: T, b: T): T => {
//     return a + b // TODO
//   }
//   sum<number>(1, 2)
// }

// 类型别名
type Cart<T> = { list: T[] } | T[]
let c1: Cart<string> = { list: ['1'] }
let c2: Cart<number> = [2]

// Interface 与 type
